#!/bin/ksh

#set -x

# V A R I A B L E S 

level=0
myName=$(basename $0)
dFlag=
sFlag=
tFlag=

# F U N C T I O N S

#
# All functions with names ending in _f provide formatted output and are aware of the tex or notex mode
# All other functions provide raw output
#

function print_usage
{
# needs param: none
# returns:     raw usage info
# called by:   many
# calls:       none

	printf "Usage:\t%s [-d] [-s|-t]\n" ${myName}
	printf "\t-d: debug mode\n"
	printf "\t-s: screen (notex) output mode, the default\n"
	printf "\t-t: .tex output mode\n"
}

function lowerCase
{
# needs param: string
# returns:     lower case string
# called by:   many
# calls:       none

	echo $1 | tr 'ABCDEFGHIJKLMNOPQRSTUVXYZ' 'abcdefghijklmnopqrstuvwxyz'
}

function check_root
{
# needs param: none
# returns:     none
# called by:   main
# calls:       none

	if [ $LOGNAME != root ]
	then
		echo This script must be run as root!
		exit
	fi
}

function levelSpace
{
# needs param: level
# returns:     string of level*2 spaces (0,2,4,6,...)
# called by:   many
# calls:       none

	myLevel=$1
	levelSpace=
	oneTab='\t'
	while [ ${myLevel} -gt 0 ]
	do
		levelSpace=${levelSpace}${oneTab}
		(( myLevel = myLevel -1 ))
	done
	printf "%s" ${levelSpace}
}

function print_header_f
{
# needs param: level
# returns:     formatted document header
# called by:   main
# calls:       get_hostname, get_mt, get_sn

	level=$1
	if [ ! -z "$tFlag" ]
	then
		echo "\\documentclass{article}"
		echo "\\\\title{$(get_hostname)}"
		echo "\\\\author{Collector v0.1}"
		echo "\\date{\\\\today}"
		echo "\\\\begin{document}"
		echo "\\maketitle"
		echo "\\\\tableofcontents"
	else
		#echo "$(get_hostname) (machine type: $(get_mt), serial number: $(get_sn))"
		printf "$(levelSpace ${level})%s (machine type: %s, serial number: %s)\n" $(get_hostname) $(get_mt) $(get_sn)
	fi
}

function print_trailer_f
{
# needs param: none
# returns:     formatted document trailer
# called by:   main
# calls:       none

	if [ ! -z "$tFlag" ]
	then
		echo '\end{document}'
	fi
}

function print_imageType_f
{
# needs param: none
# returns:     formatted OS type: LPAR or standalone
# called by:   main
# calls:       get_lparId

	if [ ! -z "$tFlag" ]
        then
		echo FIXME: TEX imageType
	else
		if [ $(get_lparId) -ne 0 ]
		then
			lparstat -i | grep ^Type | awk '{print $3}' | read lparType
			lparstat -i | grep ^Mode | awk '{print $3}' | read lparMode
			printf "$(levelSpace ${level})This system is a %s type and %s mode LPAR.\n" $(lowerCase ${lparType}) $(lowerCase ${lparMode})
			printf "$(levelSpace ${level})LPAR ID: %s\n" $(get_lparId)
		else
			printf "$(levelSpace ${level})This system is a standalone box.\n" 
		fi
	fi
}

function print_general_f
{
# needs param: none
# returns:     formatted general information
# called by:   main
# calls:       none

	if [ ! -z "$tFlag" ]
        then
		echo FIXME: TEX general
	else
		oslevel -s | read curOS
		oslevel -qs 2>/dev/null | head -1 | read latestOS
		if [ ${curOS} = ${latestOS} ]
		then
			printf "$(levelSpace ${level})OS level: %s OK\n" ${curOS}
		else
			printf "$(levelSpace ${level})OS level: %s, latest known level %s\n" ${curOS} ${latestOS}
		fi
		lparstat -i | grep "Entitled Capacity" | read j1 j2 j3 entCPU j5
		lparstat -i | grep "Minimum Capacity" | read j1 j2 j3 minCPU j5
		lparstat -i | grep "Maximum Capacity" | read j1 j2 j3 maxCPU j5
		lparstat -i | grep "Variable Capacity Weight" | read j1 j2 j3 j4 weightCPU j6
		printf "$(levelSpace ${level})CPU: entitled %s, weight %s, minimum %s, maximum %s\n" ${entCPU} ${weightCPU} ${minCPU} ${maxCPU}
		lparstat -i | grep "Online Memory"| read j1 j2 j3 onlineMemory j5
		lparstat -i | grep "Minimum Memory"| read j1 j2 j3 minMemory j5
		lparstat -i | grep "Maximum Memory"| read j1 j2 j3 maxMemory j5
		printf "$(levelSpace ${level})LPAR memory: online %s MB, minimum %s MB, maximum %s MB\n" ${onlineMemory} ${minMemory} ${maxMemory} 
	fi	
}

function get_lparId
{
# needs param: none
# returns:     raw LPAR id, a single number. if 0, the system is standalone
# called by:   ????
# calls:       none

	uname -L | read lparId hostName
	echo ${lparId}
}

function get_mt
{
# needs param: none
# returns:     raw machine type, in the form of TTTT-MMM, where T is type and M is model
# called by:   print_header_f
# calls:       none

	lsattr -El sys0 -a modelname -F value | cut -d',' -f2 | read mt
	echo ${mt}
}

function get_sn
{
# needs param: none
# returns:     raw serial number, in the form of OO-SSSSS, where O is origin and S is serial
# called by:   print_header_f
# calls:       none

	lsattr -El sys0 -a systemid -F value | cut -d',' -f2 | cut -c 3-4 | read origin
	lsattr -El sys0 -a systemid -F value | cut -d',' -f2 | cut -c 5-9 | read serial
	echo ${origin}-${serial}
}

function get_hostname
{
# needs param: none
# returns:     raw hostname
# called by:   print_header_f,get_tcpip_f
# calls:       none

	hostname
}

function get_network_adapters_f
{
# needs param: none
# returns:     formatted list of network adapters
# called by:   get_network
# calls:       get_virtual_network_adapter_macs,get_network_interfaces_f

	if [ ! -z "$tFlag" ]
	then
		echo FIXME: TEX network adapters
	else
		lsdev -Cc adapter -s vdevice -t IBM,l-lan -F name | wc -l | read number
		if [ ${number} -eq 0 ]
		then
			printf "$(levelSpace ${level})No virtual ethernet adapters on this system.\n"
		else
			printf "$(levelSpace ${level})Virtual network adapters:\n"
			(( level = level + 1 ))
			lsdev -Cc adapter -s vdevice -t IBM,l-lan -F name | while read device
			do
				printf "$(levelSpace ${level})Adapter %s, PVID: %s, VIDs: %s, MAC address %s, location %s\n" ${device} $(get_virtual_adapter_pvid ${device}) $(get_virtual_adapter_vids ${device}) $(get_virtual_network_adapter_macs ${device} | cut -f2) $(get_device_location ${device})
				get_network_interfaces_f ${device}
			done
		fi
		(( level = level - 1 ))
		printf "$(levelSpace ${level})No physical ethernet adapters on this system.\n"
	fi
}

function get_virtual_network_adapter_macs
{
# needs param: adapter device name
# returns:     space separated list of two forms of the same MAC address (32284F48026A 32:28:4f:48:02:6a)
# called by:   get_network_adapters
# calls:       none

	device=$1
	#lscfg -vl ${device} | grep "Network Address" | cut -c 37-49 | read mac1
	entstat -d ent0 | grep "Hardware Address:" | cut -c 19-35 | read mac2
	#printf "${mac1} ${mac2}"
	printf "${mac2}\n"
}

function get_virtual_adapter_pvid
{
# needs param: adapter device name
# returns:     PVID
# called by:   get_network_adapters
# calls:       none

	device=$1
	entstat -d ${device} | grep PVID | grep VIDs > /dev/null 2>&1
	case $? in
		0)
			entstat -d ${device} | grep PVID | grep VIDs | awk '{print $2}'
			;;
		1)
			entstat -d ${device} | grep "Port VLAN ID:" | awk '{print $4}'
			;;
		*)
			printf "???\n"
			;;
	esac
}

function get_virtual_adapter_vids
{
# needs param: adapter device name
# returns:     VIDs
# called by:   get_network_adapters
# calls:       none

	device=$1
	# lowerCase $(entstat -d ${device} | grep PVID | grep VIDs | awk '{print $4}')
	entstat -d ${device} | grep PVID | grep VIDs > /dev/null 2>&1
        case $? in
                0)
			lowerCase $(entstat -d ${device} | grep PVID | grep VIDs | awk '{print $4}')
			;;
		1)
			lowerCase $(entstat -d ${device} | grep "VLAN Tag IDs:" | awk '{print $4}')
			;;
		*)
			printf "???\n"
			;;
	esac

}

function get_device_location
{
# needs param: adapter device name
# returns:     device location string
# called by:   get_network_adapters
# calls:       none

	device=$1
	lscfg -vl ${device} | head -1 | awk '{print $2}'
}

function get_network_interfaces_f
{
# needs param: adapter device name (ent0) 
# returns:     formatted list of all network interfaces on a given adapter
# called by:   get_network
# calls:       none

	device=$1

	if [ ! -z "$tFlag" ]
	then
		echo FIXME: TEX get_network_interfaces
	else
		echo ${device} | cut -c 1-3 | read ifType
		if [ ${ifType} != ent ]
		then
			printf "$(levelSpace ${level})Unknown adapter type: %s" ${device}
		else
			echo ${device} | cut -c 4 | read ifNumber 
			lsattr -El en${ifNumber} -a netaddr -F value | read ifNetaddr
			if [ ! -z "$ifNetaddr" ]
			then
				lsattr -El en${ifNumber} -a state -F value | read ifState
				lsattr -El en${ifNumber} -a netmask -F value | read ifMask
				printf "$(levelSpace ${level})Inteface: %s, state: %s, address: %s, netmask: %s\n" en${ifNumber} ${ifState} ${ifNetaddr} ${ifMask}
			else	
				printf "$(levelSpace ${level})Interface %s not configured." en${ifNumber}
			fi 
		fi
	fi
}

function get_tcpip_f
{
# needs param: none
# returns:     formatted TCP/IP information
# called by:   get_network
# calls:       

	if [ ! -z "$tFlag" ]
	then
		echo FIXME: TEX tcpip	
	else
		printf "$(levelSpace ${level})Hostname: $(get_hostname)\n"
		numGws=0
		netstat -rn | grep default | while read j1 gw rest
		do
			printf "$(levelSpace ${level})Default gateway: %s\n" ${gw}
			(( numGws = numGws + 1 ))
		done
		case ${numGws} in
			0)	printf "No active gateways.";; 
			1)	;;
			*)	printf "More than one gateways active!";;
		esac 

		
	fi
}

function get_namerslv_f
{
# needs param: none
# returns:     formatted name resolving information
# called by:   get_network
# calls:

	if [ ! -z "$tFlag" ]
        then
		echo FIXME: TEX namerslv
	else
		counter=0
		namerslv -s -I | while read j1 dnsserver j2
		do
			(( counter = counter + 1 ))	
			printf "$(levelSpace ${level})Domain name server (%s): %s\n" ${counter} ${dnsserver}
		done
		counter=0
		namerslv -s -n | while read j1 domain j2
		do
			(( counter = counter + 1 ))
			printf "$(levelSpace ${level})Domain name: %s\n" ${domain}
		done
		if [ ${counter} -ne 1 ]
		then
			printf "$(levelSpace ${level})Multiple domain names defined!\n"
		fi
	fi

}

function get_network
{
# needs param: none
# returns:     formatted network information
# called by:   main
# calls:       get_network_adapters, get_network_interfacesm, get_tcpip_f

get_tcpip_f
get_namerslv_f
printf "$(levelSpace ${level})Network adapters:\n"
(( level = level + 1 ))
get_network_adapters_f
}

function get_storage
{
# needs param: none
# returns:     n/a
# called by:   main
# calls	:      get_vgs_f, get_disks_f

	get_vgs_f
	get_disks_f
}

function check_mirr_status
{
# needs param: vgname
# returns:     mirror status
# called by:   get_disks_f
# calls:	none

	vg=$1
	result=OK
	lsvg ${vg} | grep "TOTAL PVs" | read j1 j2 numDisks rest
	if [ ${numDisks} -gt 1 ]
	then	
		lsvg -l ${vg} | tail -n +3 | grep -v sysdump | while read lv type lps pps pvs state mp
		do
			(( lps = 2*lps ))
			state=$(echo ${state} | cut -d/ -f2)
			if [ ${lps} -ne ${pps} -o ${pvs} -lt 2  -o ${state} != syncd ]
			then
				result=ERROR
			fi		
		done	
	fi
	echo ${result}
}

function get_vgs_f
{
# needs param: none
# returns:     formatted vg information
# called by:   get_storage
# calls:       check_mirr_status 

	if [ ! -z "$tFlag" ]
        then	
		echo FIXME: TEX vgs 
	else
		printf "$(levelSpace ${level})Volume groups:\n"
		(( level = level + 1 ))
		for vg in rootvg $(lsvg -o | grep -v rootvg)
		do
			printf "$(levelSpace ${level})%s: " ${vg}
			if [ ${vg} = rootvg ]
			then
				# if VG is rootvg
				lsvg rootvg | grep "TOTAL PVs" | read j1 j2 numDisks rest
				onlineStatus=ONLINE
				mirrStatus=$(check_mirr_status rootvg)
				lsvg -l rootvg | grep sysdump | wc -l | read numDump
				printf "VG has %s disk(s) and is %s, mirror status is %s, number of dump LVs is %s.\n" ${numDisks} ${onlineStatus} ${mirrStatus} ${numDump}
			else
				# if VG is NOT rootvg
				lsvg -o | grep -x ${vg} > /dev/null 2>&1
				if [ $? -eq 0 ]
				then
					# if VG is ONLINE
					onlineStatus=ONLINE
					lsvg ${vg} | grep "TOTAL PVs" | read j1 j2 numDisks rest
					mirrStatus=$(check_mirr_status ${vg})
				else
					# if VG is OFFLINE
					onlineStatus=OFFLINE
					lspv | grep -x ${vg} | wc -l | read numDisks
					mirrStatus=UNKNOWN
				fi
			printf "VG has %s disk(s) and is %s, mirror status is %s.\n" ${numDisks} ${onlineStatus} ${mirrStatus}
			fi	
		done	
		(( level = level - 1 ))
	fi
}

function get_disks_f
{
# needs param: none
# returns:     formatted disk information
# called by:   get_storage
# calls:       none 

        if [ ! -z "$tFlag" ]
        then
                echo FIXME: TEX disks
        else
		printf "$(levelSpace ${level})Disks:\n"
		(( level = level + 1 ))
		lspv | sort | while read disk pvid vg status
		do
			if [ ${vg} = None ]
			then
				diskVg="not in VG"
			else
				diskVg="member of ${vg}"
			fi
			lsvg -o | grep -x ${vg} > /dev/null 2>&1
			if [ $? -eq 0 ]
			then
				# if VG is ONLINE
				lspv ${disk} | grep "TOTAL PPs" | read j1 j2 totPps rest
				lspv ${disk} | grep "USED PPs"  | read j1 j2 usdPps rest
				diskFull=$(printf "%s\n" "scale=2; ${usdPps}/${totPps}*100" | bc)
				diskFull="${diskFull}% full,"
			else
				# if VG is OFFLINE
				diskFull=""
			fi
			diskSize=$(getconf DISK_SIZE /dev/${disk})
			diskDesc=$(lsdev -l ${disk} -F description)
			printf "$(levelSpace ${level})%s: %s, size %s MB, %s type %s.\n" ${disk} "${diskVg}" "${diskSize}" "${diskFull}" "${diskDesc}"
		done	
		lsdev -Cc disk -S d | wc -l | read diskDefined	
		case ${diskDefined} in
			0)
				;;
			1)
				printf "$(levelSpace ${level})1 disk is in the DEFINED state!\n"
				;;
			*)
				printf "$(levelSpace ${level})%s disks are in the DEFINED state!\n" ${diskDefined}
				;;
		esac
		(( level = level - 1 ))
	fi

}

# M A I N

# will be re-enabled when final
#check_root

while getopts dst opt
do
	case ${opt} in
		d)	dFlag=1
			set -x
			;;
		s)	sFlag=1
			;;
		t)	tFlag=1
			;;
		?)	print_usage
			exit 1
			;;
	esac
done

if [ "$sFlag" = "1" -a "$tFlag" = "1" ]
then
	printf "Flags -s and -t are mutually exclusive.\n"
	print_usage
	exit 1
fi

#if [ ! -z "$dFlag" ]; then
	#printf "Option -d specified\n"
#fi
#if [ ! -z "$sFlag" ]; then
#	printf "Option -s specified\n"
#fi
#
#if [ ! -z "$tFlag" ]; then
#	printf 'Option -t specified\n' 
#fi

#shift $(($OPTIND -1))
#printf "Remaining arguments are: %s\n" "$*"


level=0
print_header_f ${level}
level=1
print_imageType_f
print_general_f
#get_lparId
get_network
(( level = level - 1 ))
get_storage
print_trailer_f
